package tool.soft

import akka.stream.Materializer
import dao._
import implicits.Implicits._
import models.Tables._
import org.joda.time.DateTime
import play.api.data.FormBinding
import play.api.i18n.Messages
import play.api.libs.ws.WSClient
import play.api.mvc.{AnyContent, Request}
import play.twirl.api.Html
import shared.Pojo.{AllPlotData, PreprocessSoftData, PreprocessSoftT}
import shared.SharedTool
import tool.Pojo._
import tool.plot.Pca2D
import tool.soft.AllSoft.SoftBT
import tool.workflow.soft.AllSubSoft
import tool.{FormTool, Tool}
import utils.Utils

import java.io.File
import scala.collection.immutable.SeqMap
import upickle.default._

/** Created by yz on 16/9/2020
  */
object PreprocessSoft extends PreprocessSoftT with SoftBT {

  override def getResultHtml(missionId: Int)(implicit request: Request[AnyContent], messages: Messages): Html = {
    views.html.user.mission.preprocessResult(missionId)
  }

  override def getFileInfos(workspaceDir: File, index: Int)(implicit
      matrixFileDataDao: MatrixFileDataDao,
      messages: Messages
  ): List[FileInfoData] = {
    val data = getData(workspaceDir)
    val files = workspaceDir.listFiles().filter { x =>
      x.getName.matches("^\\d+.*$") && !x.getName.endsWith(".txt")
    }
    val fileInfos = data.datas.map(_.kind).zipWithIndex.map { case (kind, i) =>
      val curSoft = AllSubSoft.kindSoftMap(kind)
      val file = files.find(_.getName.startsWith(s"${i + 1}.")).get
      FileInfoData(file.getName, messages(curSoft.nameStr))
    }
    val pcaFileInfos = List(
      FileInfoData("PCA_Score_2D.pdf", messages("pCAScore2D"))
    )
    fileInfos ::: pcaFileInfos
  }

  override def produceConfigFile(workspaceDir: File, index: Int)(implicit
      request: Request[AnyContent],
      formBinding: FormBinding
  ) = {
    Utils.t2ConfigFileWithDefault(data, Tool.getCalculateConfigJsonFile(workspaceDir))
    Utils.t2ConfigFile(workspaceDir, data)

    val colorData = NaIdentifyColorData(data.datas.map(_.naColor))
    Utils.t2ConfigFile(colorData, Tool.getColorJsonFile(workspaceDir))
    tool.plot.Pca2D.initConfigFile(workspaceDir, "")
  }

  def getArg(implicit request: Request[AnyContent], messages: Messages, formBinding: FormBinding): ujson.Value = {
    ujson.Obj()
  }

  def getData(workspaceDir: File) = {
    val value = Utils.configFile2Json(workspaceDir)
    value.transform(reader[PreprocessSoftData])
  }

  override def getCommandData(workspaceDir: File, resultDir: File, index: Int): List[CommandData] = {
    val solutionFile = new File(Tool.dataDir, "color_solution/color_solution_1.txt")
    val groupFile = new File(workspaceDir, "group.txt")
    val data = getData(workspaceDir)
    val indexMap = SharedTool.getIndexMap(data.datas.map(_.kind))
    val commands = data.datas.map(_.kind).zipWithIndex.map { kindI =>
      val (kind, i) = kindI
      val curSoft = AllSubSoft.kindSoftMap(kind)
      val index = indexMap(i)
      val si = List(i + 1, index).mkString(";")
      curSoft.getCommand(si)
    }
    val i = data.datas.size
    val rawDataFile = new File(workspaceDir, s"${i}.result.txt")
    val pcaCommands =
      s"""
         |${Tool.rScript} ${new File(
          Tool.rPath,
          "produce_sample_color.R"
        ).unixPath} --g ${groupFile.unixPath}  --solution ${solutionFile.unixPath}
         |${Tool.rScript} ${new File(Tool.rPath, "pca_calculate.R").unixPath} --i ${rawDataFile.unixPath}
         |""".stripMargin
    val plotCommand = tool.plot.Pca2D.getCommand(workspaceDir, idStr = "")
    val finalCommands = commands :+ pcaCommands :+ plotCommand
    List(CommandData(workspaceDir, finalCommands))
  }

  override def resultDeal(workspaceDir: File, resultDir: File)(implicit
      ws: WSClient,
      materializer: Materializer
  ): Unit = {
    val data = getData(workspaceDir)
    val indexMap = SharedTool.getIndexMap(data.datas.map(_.kind))
    val commands = data.datas.map(_.kind).zipWithIndex.map { kindI =>
      val (kind, i) = kindI
      val curSoft = AllSubSoft.kindSoftMap(kind)
      val index = indexMap(i)
      val si = List(i + 1, index).mkString(";")
      curSoft.execAfterCommand(workspaceDir, resultDir, si)
    }
    Tool.preprocessResultDeal(workspaceDir, resultDir)
  }

  override def getHtml(missionName: String, missionId: Option[Int])(implicit
      request: Request[AnyContent],
      messages: Messages
  ): Html = {
    views.html.user.soft.preprocess(missionName, missionId)
  }

  override def getMission(implicit
      request: Request[AnyContent],
      matrixFileDataDao: MatrixFileDataDao,
      messages: Messages,
      formBinding: FormBinding
  ): _root_.models.Tables.MissionRow = {
    val argJson = getArg
    val input = if (data.hasGroup) {
      List(data.file, data.groupFile)
    } else {
      List(data.file)
    }
    MissionRow(
      id = 0,
      missionName = s"${data.missionName}",
      kind = nameStr,
      userId = userId,
      startTime = new DateTime(),
      state = "preparing",
      arg = argJson,
      input = input
    )
  }

  override def produceInputFile(
      workspaceDir: File
  )(implicit request: Request[AnyContent], dao: MyDao, formBinding: FormBinding): Any = {
    val rawDataFile = new File(workspaceDir, "0.result.txt")
    Tool.produceRawDataFile(userId, data.file, rawDataFile)
    val groupFile = new File(workspaceDir, "group.txt")
    if (data.hasGroup) {
      Tool.produceRawGroupFile(userId, data.groupFile, groupFile)
    } else {
      Tool.produceNoGroupFile(rawDataFile, groupFile)
    }
  }

  override def data(implicit request: Request[AnyContent], formBinding: FormBinding) = {
    Tool.transformRq.transform(reader[PreprocessSoftData])
  }

}
